/*
 * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
/*
 * Copyright 2001-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.sun.org.apache.xerces.internal.impl.xs.traversers;

import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeFacetException;
import com.sun.org.apache.xerces.internal.impl.dv.SchemaDVFactory;
import com.sun.org.apache.xerces.internal.impl.dv.XSFacets;
import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
import com.sun.org.apache.xerces.internal.impl.dv.xs.XSSimpleTypeDecl;
import com.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar;
import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
import com.sun.org.apache.xerces.internal.impl.xs.XSAnnotationImpl;
import com.sun.org.apache.xerces.internal.impl.xs.XSAttributeGroupDecl;
import com.sun.org.apache.xerces.internal.impl.xs.XSAttributeUseImpl;
import com.sun.org.apache.xerces.internal.impl.xs.XSComplexTypeDecl;
import com.sun.org.apache.xerces.internal.impl.xs.XSConstraints;
import com.sun.org.apache.xerces.internal.impl.xs.XSModelGroupImpl;
import com.sun.org.apache.xerces.internal.impl.xs.XSParticleDecl;
import com.sun.org.apache.xerces.internal.impl.xs.XSWildcardDecl;
import com.sun.org.apache.xerces.internal.impl.xs.util.XInt;
import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
import com.sun.org.apache.xerces.internal.util.DOMUtil;
import com.sun.org.apache.xerces.internal.xni.QName;
import com.sun.org.apache.xerces.internal.xs.XSAttributeUse;
import com.sun.org.apache.xerces.internal.xs.XSConstants;
import com.sun.org.apache.xerces.internal.xs.XSObjectList;
import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
import org.w3c.dom.Element;

/**
 * A complex type definition schema component traverser.
 *
 * <complexType
 * abstract = boolean : false
 * block = (#all | List of (extension | restriction))
 * final = (#all | List of (extension | restriction))
 * id = ID
 * mixed = boolean : false
 * name = NCName
 * {any attributes with non-schema namespace . . .}>
 * Content: (annotation?, (simpleContent | complexContent |
 * ((group | all | choice | sequence)?,
 * ((attribute | attributeGroup)*, anyAttribute?))))
 * </complexType>
 *
 * @version $Id: XSDComplexTypeTraverser.java,v 1.8 2010-11-01 04:40:02 joehw Exp $
 * @xerces.internal
 */

class XSDComplexTypeTraverser extends XSDAbstractParticleTraverser {

  // size of stack to hold globals:
  private final static int GLOBAL_NUM = 11;

  private static XSParticleDecl fErrorContent = null;
  private static XSWildcardDecl fErrorWildcard = null;

  private static XSParticleDecl getErrorContent() {
    if (fErrorContent == null) {
      XSParticleDecl particle = new XSParticleDecl();
      particle.fType = XSParticleDecl.PARTICLE_WILDCARD;
      particle.fValue = getErrorWildcard();
      particle.fMinOccurs = 0;
      particle.fMaxOccurs = SchemaSymbols.OCCURRENCE_UNBOUNDED;
      XSModelGroupImpl group = new XSModelGroupImpl();
      group.fCompositor = XSModelGroupImpl.MODELGROUP_SEQUENCE;
      group.fParticleCount = 1;
      group.fParticles = new XSParticleDecl[1];
      group.fParticles[0] = particle;
      XSParticleDecl errorContent = new XSParticleDecl();
      errorContent.fType = XSParticleDecl.PARTICLE_MODELGROUP;
      errorContent.fValue = group;
      fErrorContent = errorContent;
    }
    return fErrorContent;
  }

  private static XSWildcardDecl getErrorWildcard() {
    if (fErrorWildcard == null) {
      XSWildcardDecl wildcard = new XSWildcardDecl();
      wildcard.fProcessContents = XSWildcardDecl.PC_SKIP;
      fErrorWildcard = wildcard;
    }
    return fErrorWildcard;
  }

  // globals for building XSComplexTypeDecls
  private String fName = null;
  private String fTargetNamespace = null;
  private short fDerivedBy = XSConstants.DERIVATION_RESTRICTION;
  private short fFinal = XSConstants.DERIVATION_NONE;
  private short fBlock = XSConstants.DERIVATION_NONE;
  private short fContentType = XSComplexTypeDecl.CONTENTTYPE_EMPTY;
  private XSTypeDefinition fBaseType = null;
  private XSAttributeGroupDecl fAttrGrp = null;
  private XSSimpleType fXSSimpleType = null;
  private XSParticleDecl fParticle = null;
  private boolean fIsAbstract = false;
  private XSComplexTypeDecl fComplexTypeDecl = null;
  private XSAnnotationImpl[] fAnnotations = null;

  // our own little stack to retain state when getGlobalDecls is called:
  private Object[] fGlobalStore = null;
  private int fGlobalStorePos = 0;

  XSDComplexTypeTraverser(XSDHandler handler,
      XSAttributeChecker gAttrCheck) {
    super(handler, gAttrCheck);
  }


  private static final boolean DEBUG = false;

  private static final class ComplexTypeRecoverableError extends Exception {

    private static final long serialVersionUID = 6802729912091130335L;

    Object[] errorSubstText = null;
    Element errorElem = null;

    ComplexTypeRecoverableError() {
      super();
    }

    ComplexTypeRecoverableError(String msgKey, Object[] args, Element e) {
      super(msgKey);
      errorSubstText = args;
      errorElem = e;
    }

  }

  /**
   * Traverse local complexType declarations
   *
   * @return XSComplexTypeDecl
   */
  XSComplexTypeDecl traverseLocal(Element complexTypeNode,
      XSDocumentInfo schemaDoc,
      SchemaGrammar grammar) {

    Object[] attrValues = fAttrChecker.checkAttributes(complexTypeNode, false,
        schemaDoc);
    String complexTypeName = genAnonTypeName(complexTypeNode);
    contentBackup();
    XSComplexTypeDecl type = traverseComplexTypeDecl(complexTypeNode,
        complexTypeName, attrValues, schemaDoc, grammar);
    contentRestore();
    // need to add the type to the grammar for later constraint checking
    grammar.addComplexTypeDecl(type, fSchemaHandler.element2Locator(complexTypeNode));
    type.setIsAnonymous();
    fAttrChecker.returnAttrArray(attrValues, schemaDoc);

    return type;
  }

  /**
   * Traverse global complexType declarations
   *
   * @return XSComplexTypeDecXSComplexTypeDecl
   */
  XSComplexTypeDecl traverseGlobal(Element complexTypeNode,
      XSDocumentInfo schemaDoc,
      SchemaGrammar grammar) {

    Object[] attrValues = fAttrChecker.checkAttributes(complexTypeNode, true,
        schemaDoc);
    String complexTypeName = (String) attrValues[XSAttributeChecker.ATTIDX_NAME];
    contentBackup();
    XSComplexTypeDecl type = traverseComplexTypeDecl(complexTypeNode,
        complexTypeName, attrValues, schemaDoc, grammar);
    contentRestore();
    // need to add the type to the grammar for later constraint checking
    grammar.addComplexTypeDecl(type, fSchemaHandler.element2Locator(complexTypeNode));

    if (complexTypeName == null) {
      reportSchemaError("s4s-att-must-appear",
          new Object[]{SchemaSymbols.ELT_COMPLEXTYPE, SchemaSymbols.ATT_NAME}, complexTypeNode);
      type = null;
    } else {
      if (grammar.getGlobalTypeDecl(type.getName()) == null) {
        grammar.addGlobalComplexTypeDecl(type);
      }

      // also add it to extended map
      final String loc = fSchemaHandler.schemaDocument2SystemId(schemaDoc);
      final XSTypeDefinition type2 = grammar.getGlobalTypeDecl(type.getName(), loc);
      if (type2 == null) {
        grammar.addGlobalComplexTypeDecl(type, loc);
      }

      // handle duplicates
      if (fSchemaHandler.fTolerateDuplicates) {
        if (type2 != null) {
          if (type2 instanceof XSComplexTypeDecl) {
            type = (XSComplexTypeDecl) type2;
          }
        }
        fSchemaHandler.addGlobalTypeDecl(type);
      }
    }

    fAttrChecker.returnAttrArray(attrValues, schemaDoc);

    return type;
  }


  private XSComplexTypeDecl traverseComplexTypeDecl(Element complexTypeDecl,
      String complexTypeName,
      Object[] attrValues,
      XSDocumentInfo schemaDoc,
      SchemaGrammar grammar) {

    fComplexTypeDecl = new XSComplexTypeDecl();
    fAttrGrp = new XSAttributeGroupDecl();
    Boolean abstractAtt = (Boolean) attrValues[XSAttributeChecker.ATTIDX_ABSTRACT];
    XInt blockAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_BLOCK];
    Boolean mixedAtt = (Boolean) attrValues[XSAttributeChecker.ATTIDX_MIXED];
    XInt finalAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_FINAL];

    fName = complexTypeName;
    fComplexTypeDecl.setName(fName);
    fTargetNamespace = schemaDoc.fTargetNamespace;

    fBlock = blockAtt == null ? schemaDoc.fBlockDefault : blockAtt.shortValue();
    fFinal = finalAtt == null ? schemaDoc.fFinalDefault : finalAtt.shortValue();
    //discard valid Block/Final 'Default' values that are invalid for Block/Final
    fBlock &= (XSConstants.DERIVATION_EXTENSION | XSConstants.DERIVATION_RESTRICTION);
    fFinal &= (XSConstants.DERIVATION_EXTENSION | XSConstants.DERIVATION_RESTRICTION);

    fIsAbstract = (abstractAtt != null && abstractAtt.booleanValue());
    fAnnotations = null;

    Element child = null;

    try {
      // ---------------------------------------------------------------
      // First, handle any ANNOTATION declaration and get next child
      // ---------------------------------------------------------------
      child = DOMUtil.getFirstChildElement(complexTypeDecl);
      if (child != null) {
        if (DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
          addAnnotation(traverseAnnotationDecl(child, attrValues, false, schemaDoc));
          child = DOMUtil.getNextSiblingElement(child);
        } else {
          String text = DOMUtil.getSyntheticAnnotation(complexTypeDecl);
          if (text != null) {
            addAnnotation(
                traverseSyntheticAnnotation(complexTypeDecl, text, attrValues, false, schemaDoc));
          }
        }
        if (child != null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
          throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
              new Object[]{fName, SchemaSymbols.ELT_ANNOTATION},
              child);
        }
      } else {
        String text = DOMUtil.getSyntheticAnnotation(complexTypeDecl);
        if (text != null) {
          addAnnotation(
              traverseSyntheticAnnotation(complexTypeDecl, text, attrValues, false, schemaDoc));
        }
      }
      // ---------------------------------------------------------------
      // Process the content of the complex type definition
      // ---------------------------------------------------------------
      if (child == null) {
        //
        // EMPTY complexType with complexContent
        //

        // set the base to the anyType
        fBaseType = SchemaGrammar.fAnyType;
        fDerivedBy = XSConstants.DERIVATION_RESTRICTION;
        processComplexContent(child, mixedAtt.booleanValue(), false,
            schemaDoc, grammar);
      } else if (DOMUtil.getLocalName(child).equals
          (SchemaSymbols.ELT_SIMPLECONTENT)) {
        //
        // SIMPLE CONTENT
        //
        traverseSimpleContent(child, schemaDoc, grammar);
        Element elemTmp = DOMUtil.getNextSiblingElement(child);
        if (elemTmp != null) {
          String siblingName = DOMUtil.getLocalName(elemTmp);
          throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
              new Object[]{fName, siblingName},
              elemTmp);
        }
      } else if (DOMUtil.getLocalName(child).equals
          (SchemaSymbols.ELT_COMPLEXCONTENT)) {
        traverseComplexContent(child, mixedAtt.booleanValue(),
            schemaDoc, grammar);
        Element elemTmp = DOMUtil.getNextSiblingElement(child);
        if (elemTmp != null) {
          String siblingName = DOMUtil.getLocalName(elemTmp);
          throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
              new Object[]{fName, siblingName},
              elemTmp);
        }
      } else {
        //
        // We must have ....
        // GROUP, ALL, SEQUENCE or CHOICE, followed by optional attributes
        // Note that it's possible that only attributes are specified.
        //

        // set the base to the anyType
        fBaseType = SchemaGrammar.fAnyType;
        fDerivedBy = XSConstants.DERIVATION_RESTRICTION;
        processComplexContent(child, mixedAtt.booleanValue(), false,
            schemaDoc, grammar);
      }

    } catch (ComplexTypeRecoverableError e) {
      handleComplexTypeError(e.getMessage(), e.errorSubstText,
          e.errorElem);
    }

    if (DEBUG) {
      System.out.println(fName);
    }
    fComplexTypeDecl.setValues(fName, fTargetNamespace, fBaseType,
        fDerivedBy, fFinal, fBlock, fContentType, fIsAbstract,
        fAttrGrp, fXSSimpleType, fParticle, new XSObjectListImpl(fAnnotations,
            fAnnotations == null ? 0 : fAnnotations.length));
    return fComplexTypeDecl;
  }


  private void traverseSimpleContent(Element simpleContentElement,
      XSDocumentInfo schemaDoc,
      SchemaGrammar grammar)
      throws ComplexTypeRecoverableError {

    Object[] simpleContentAttrValues = fAttrChecker.checkAttributes(simpleContentElement, false,
        schemaDoc);

    // -----------------------------------------------------------------------
    // Set content type
    // -----------------------------------------------------------------------
    fContentType = XSComplexTypeDecl.CONTENTTYPE_SIMPLE;
    fParticle = null;

    Element simpleContent = DOMUtil.getFirstChildElement(simpleContentElement);
    if (simpleContent != null && DOMUtil.getLocalName(simpleContent)
        .equals(SchemaSymbols.ELT_ANNOTATION)) {
      addAnnotation(
          traverseAnnotationDecl(simpleContent, simpleContentAttrValues, false, schemaDoc));
      simpleContent = DOMUtil.getNextSiblingElement(simpleContent);
    } else {
      String text = DOMUtil.getSyntheticAnnotation(simpleContentElement);
      if (text != null) {
        addAnnotation(
            traverseSyntheticAnnotation(simpleContentElement, text, simpleContentAttrValues, false,
                schemaDoc));
      }
    }

    // If there are no children, return
    if (simpleContent == null) {
      fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
      throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.2",
          new Object[]{fName, SchemaSymbols.ELT_SIMPLECONTENT},
          simpleContentElement);
    }

    // -----------------------------------------------------------------------
    // The content should be either "restriction" or "extension"
    // -----------------------------------------------------------------------
    String simpleContentName = DOMUtil.getLocalName(simpleContent);
    if (simpleContentName.equals(SchemaSymbols.ELT_RESTRICTION)) {
      fDerivedBy = XSConstants.DERIVATION_RESTRICTION;
    } else if (simpleContentName.equals(SchemaSymbols.ELT_EXTENSION)) {
      fDerivedBy = XSConstants.DERIVATION_EXTENSION;
    } else {
      fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
      throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
          new Object[]{fName, simpleContentName},
          simpleContent);
    }
    Element elemTmp = DOMUtil.getNextSiblingElement(simpleContent);
    if (elemTmp != null) {
      fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
      String siblingName = DOMUtil.getLocalName(elemTmp);
      throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
          new Object[]{fName, siblingName},
          elemTmp);
    }

    Object[] derivationTypeAttrValues = fAttrChecker.checkAttributes(simpleContent, false,
        schemaDoc);
    QName baseTypeName = (QName) derivationTypeAttrValues[XSAttributeChecker.ATTIDX_BASE];

    // -----------------------------------------------------------------------
    // Need a base type.
    // -----------------------------------------------------------------------
    if (baseTypeName == null) {
      fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
      fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
      throw new ComplexTypeRecoverableError("s4s-att-must-appear",
          new Object[]{simpleContentName, "base"}, simpleContent);
    }

    XSTypeDefinition type = (XSTypeDefinition) fSchemaHandler.getGlobalDecl(schemaDoc,
        XSDHandler.TYPEDECL_TYPE, baseTypeName,
        simpleContent);
    if (type == null) {
      fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
      fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
      throw new ComplexTypeRecoverableError();
    }

    fBaseType = type;

    XSSimpleType baseValidator = null;
    XSComplexTypeDecl baseComplexType = null;
    int baseFinalSet = 0;

    // If the base type is complex, it must have simpleContent
    if ((type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)) {

      baseComplexType = (XSComplexTypeDecl) type;
      baseFinalSet = baseComplexType.getFinal();
      // base is a CT with simple content (both restriction and extension are OK)
      if (baseComplexType.getContentType() == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
        baseValidator = (XSSimpleType) baseComplexType.getSimpleType();
      }
      // base is a CT with mixed/emptiable content (only restriction is OK)
      else if (fDerivedBy == XSConstants.DERIVATION_RESTRICTION &&
          baseComplexType.getContentType() == XSComplexTypeDecl.CONTENTTYPE_MIXED &&
          ((XSParticleDecl) baseComplexType.getParticle()).emptiable()) {
      } else {
        fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
        fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
        throw new ComplexTypeRecoverableError("src-ct.2.1",
            new Object[]{fName, baseComplexType.getName()}, simpleContent);
      }
    } else {
      baseValidator = (XSSimpleType) type;
      // base is a ST (only extension is OK)
      if (fDerivedBy == XSConstants.DERIVATION_RESTRICTION) {
        fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
        fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
        throw new ComplexTypeRecoverableError("src-ct.2.1",
            new Object[]{fName, baseValidator.getName()}, simpleContent);
      }
      baseFinalSet = baseValidator.getFinal();
    }

    // -----------------------------------------------------------------------
    // Check that the base permits the derivation
    // -----------------------------------------------------------------------
    if ((baseFinalSet & fDerivedBy) != 0) {
      fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
      fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
      String errorKey = (fDerivedBy == XSConstants.DERIVATION_EXTENSION) ?
          "cos-ct-extends.1.1" : "derivation-ok-restriction.1";
      throw new ComplexTypeRecoverableError(errorKey,
          new Object[]{fName, fBaseType.getName()}, simpleContent);
    }

    // -----------------------------------------------------------------------
    // Skip over any potential annotations
    // -----------------------------------------------------------------------
    Element scElement = simpleContent;
    simpleContent = DOMUtil.getFirstChildElement(simpleContent);
    if (simpleContent != null) {
      // traverse annotation if any

      if (DOMUtil.getLocalName(simpleContent).equals(SchemaSymbols.ELT_ANNOTATION)) {
        addAnnotation(
            traverseAnnotationDecl(simpleContent, derivationTypeAttrValues, false, schemaDoc));
        simpleContent = DOMUtil.getNextSiblingElement(simpleContent);
      } else {
        String text = DOMUtil.getSyntheticAnnotation(scElement);
        if (text != null) {
          addAnnotation(
              traverseSyntheticAnnotation(scElement, text, derivationTypeAttrValues, false,
                  schemaDoc));
        }
      }

      if (simpleContent != null &&
          DOMUtil.getLocalName(simpleContent).equals(SchemaSymbols.ELT_ANNOTATION)) {
        fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
        fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
        throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
            new Object[]{fName, SchemaSymbols.ELT_ANNOTATION},
            simpleContent);
      }
    } else {
      String text = DOMUtil.getSyntheticAnnotation(scElement);
      if (text != null) {
        addAnnotation(traverseSyntheticAnnotation(scElement, text, derivationTypeAttrValues, false,
            schemaDoc));
      }
    }

    // -----------------------------------------------------------------------
    // Process a RESTRICTION
    // -----------------------------------------------------------------------
    if (fDerivedBy == XSConstants.DERIVATION_RESTRICTION) {

      // -----------------------------------------------------------------------
      // There may be a simple type definition in the restriction element
      // The data type validator will be based on it, if specified
      // -----------------------------------------------------------------------
      if (simpleContent != null &&
          DOMUtil.getLocalName(simpleContent).equals(SchemaSymbols.ELT_SIMPLETYPE)) {

        XSSimpleType dv = fSchemaHandler.fSimpleTypeTraverser.traverseLocal(
            simpleContent, schemaDoc, grammar);
        if (dv == null) {
          fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
          fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
          throw new ComplexTypeRecoverableError();
        }
        //check that this datatype validator is validly derived from the base
        //according to derivation-ok-restriction 5.1.2.1

        if (baseValidator != null &&
            !XSConstraints.checkSimpleDerivationOk(dv, baseValidator,
                baseValidator.getFinal())) {
          fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
          fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
          throw new ComplexTypeRecoverableError("derivation-ok-restriction.5.2.2.1",
              new Object[]{fName, dv.getName(), baseValidator.getName()},
              simpleContent);
        }
        baseValidator = dv;
        simpleContent = DOMUtil.getNextSiblingElement(simpleContent);
      }

      // this only happens when restricting a mixed/emptiable CT
      // but there is no <simpleType>, which is required
      if (baseValidator == null) {
        fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
        fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
        throw new ComplexTypeRecoverableError("src-ct.2.2",
            new Object[]{fName}, simpleContent);
      }

      // -----------------------------------------------------------------------
      // Traverse any facets
      // -----------------------------------------------------------------------
      Element attrNode = null;
      XSFacets facetData = null;
      short presentFacets = 0;
      short fixedFacets = 0;

      if (simpleContent != null) {
        FacetInfo fi = traverseFacets(simpleContent, baseValidator, schemaDoc);
        attrNode = fi.nodeAfterFacets;
        facetData = fi.facetdata;
        presentFacets = fi.fPresentFacets;
        fixedFacets = fi.fFixedFacets;
      }

      String name = genAnonTypeName(simpleContentElement);
      fXSSimpleType = fSchemaHandler.fDVFactory
          .createTypeRestriction(name, schemaDoc.fTargetNamespace, (short) 0, baseValidator, null);
      try {
        fValidationState.setNamespaceSupport(schemaDoc.fNamespaceSupport);
        fXSSimpleType.applyFacets(facetData, presentFacets, fixedFacets, fValidationState);
      } catch (InvalidDatatypeFacetException ex) {
        reportSchemaError(ex.getKey(), ex.getArgs(), simpleContent);
        // Recreate the type, ignoring the facets
        fXSSimpleType = fSchemaHandler.fDVFactory
            .createTypeRestriction(name, schemaDoc.fTargetNamespace, (short) 0, baseValidator,
                null);
      }
      if (fXSSimpleType instanceof XSSimpleTypeDecl) {
        ((XSSimpleTypeDecl) fXSSimpleType).setAnonymous(true);
      }

      // -----------------------------------------------------------------------
      // Traverse any attributes
      // -----------------------------------------------------------------------
      if (attrNode != null) {
        if (!isAttrOrAttrGroup(attrNode)) {
          fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
          fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
          throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
              new Object[]{fName, DOMUtil.getLocalName(attrNode)},
              attrNode);
        }
        Element node = traverseAttrsAndAttrGrps(attrNode, fAttrGrp,
            schemaDoc, grammar, fComplexTypeDecl);
        if (node != null) {
          fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
          fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
          throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
              new Object[]{fName, DOMUtil.getLocalName(node)},
              node);
        }
      }

      try {
        mergeAttributes(baseComplexType.getAttrGrp(), fAttrGrp, fName, false, simpleContentElement);
      } catch (ComplexTypeRecoverableError e) {
        fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
        fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
        throw e;
      }
      // Prohibited uses must be removed after merge for RESTRICTION
      fAttrGrp.removeProhibitedAttrs();

      Object[] errArgs = fAttrGrp.validRestrictionOf(fName, baseComplexType.getAttrGrp());
      if (errArgs != null) {
        fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
        fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
        throw new ComplexTypeRecoverableError((String) errArgs[errArgs.length - 1],
            errArgs, attrNode);
      }

    }
    // -----------------------------------------------------------------------
    // Process a EXTENSION
    // -----------------------------------------------------------------------
    else {
      fXSSimpleType = baseValidator;
      if (simpleContent != null) {
        // -----------------------------------------------------------------------
        // Traverse any attributes
        // -----------------------------------------------------------------------
        Element attrNode = simpleContent;
        if (!isAttrOrAttrGroup(attrNode)) {
          fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
          fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
          throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
              new Object[]{fName, DOMUtil.getLocalName(attrNode)},
              attrNode);
        }
        Element node = traverseAttrsAndAttrGrps(attrNode, fAttrGrp,
            schemaDoc, grammar, fComplexTypeDecl);

        if (node != null) {
          fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
          fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
          throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
              new Object[]{fName, DOMUtil.getLocalName(node)},
              node);
        }
        // Remove prohibited uses.   Should be done prior to any merge.
        fAttrGrp.removeProhibitedAttrs();
      }

      if (baseComplexType != null) {
        try {
          mergeAttributes(baseComplexType.getAttrGrp(), fAttrGrp, fName, true,
              simpleContentElement);
        } catch (ComplexTypeRecoverableError e) {
          fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
          fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
          throw e;
        }
      }
    }
    // and finally, since we've nothing more to traverse, we can
    // return the attributes (and thereby reset the namespace support)
    fAttrChecker.returnAttrArray(simpleContentAttrValues, schemaDoc);
    fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
  }

  private void traverseComplexContent(Element complexContentElement,
      boolean mixedOnType, XSDocumentInfo schemaDoc,
      SchemaGrammar grammar)
      throws ComplexTypeRecoverableError {

    Object[] complexContentAttrValues = fAttrChecker.checkAttributes(complexContentElement, false,
        schemaDoc);

    // -----------------------------------------------------------------------
    // Determine if this is mixed content
    // -----------------------------------------------------------------------
    boolean mixedContent = mixedOnType;
    Boolean mixedAtt = (Boolean) complexContentAttrValues[XSAttributeChecker.ATTIDX_MIXED];
    if (mixedAtt != null) {
      mixedContent = mixedAtt.booleanValue();
    }

    // -----------------------------------------------------------------------
    // Since the type must have complex content, set the simple type validators
    // to null
    // -----------------------------------------------------------------------
    fXSSimpleType = null;

    Element complexContent = DOMUtil.getFirstChildElement(complexContentElement);
    if (complexContent != null && DOMUtil.getLocalName(complexContent)
        .equals(SchemaSymbols.ELT_ANNOTATION)) {
      addAnnotation(
          traverseAnnotationDecl(complexContent, complexContentAttrValues, false, schemaDoc));
      complexContent = DOMUtil.getNextSiblingElement(complexContent);
    } else {
      String text = DOMUtil.getSyntheticAnnotation(complexContentElement);
      if (text != null) {
        addAnnotation(
            traverseSyntheticAnnotation(complexContentElement, text, complexContentAttrValues,
                false, schemaDoc));
      }
    }

    // If there are no children, return
    if (complexContent == null) {
      fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
      throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.2",
          new Object[]{fName, SchemaSymbols.ELT_COMPLEXCONTENT},
          complexContentElement);
    }

    // -----------------------------------------------------------------------
    // The content should be either "restriction" or "extension"
    // -----------------------------------------------------------------------
    String complexContentName = DOMUtil.getLocalName(complexContent);
    if (complexContentName.equals(SchemaSymbols.ELT_RESTRICTION)) {
      fDerivedBy = XSConstants.DERIVATION_RESTRICTION;
    } else if (complexContentName.equals(SchemaSymbols.ELT_EXTENSION)) {
      fDerivedBy = XSConstants.DERIVATION_EXTENSION;
    } else {
      fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
      throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
          new Object[]{fName, complexContentName}, complexContent);
    }
    Element elemTmp = DOMUtil.getNextSiblingElement(complexContent);
    if (elemTmp != null) {
      fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
      String siblingName = DOMUtil.getLocalName(elemTmp);
      throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
          new Object[]{fName, siblingName}, elemTmp);
    }

    Object[] derivationTypeAttrValues = fAttrChecker.checkAttributes(complexContent, false,
        schemaDoc);
    QName baseTypeName = (QName) derivationTypeAttrValues[XSAttributeChecker.ATTIDX_BASE];

    // -----------------------------------------------------------------------
    // Need a base type.  Check that it's a complex type
    // -----------------------------------------------------------------------
    if (baseTypeName == null) {
      fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
      fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
      throw new ComplexTypeRecoverableError("s4s-att-must-appear",
          new Object[]{complexContentName, "base"}, complexContent);
    }

    XSTypeDefinition type = (XSTypeDefinition) fSchemaHandler.getGlobalDecl(schemaDoc,
        XSDHandler.TYPEDECL_TYPE,
        baseTypeName,
        complexContent);

    if (type == null) {
      fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
      fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
      throw new ComplexTypeRecoverableError();
    }

    if (!(type instanceof XSComplexTypeDecl)) {
      fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
      fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
      throw new ComplexTypeRecoverableError("src-ct.1",
          new Object[]{fName, type.getName()}, complexContent);
    }
    XSComplexTypeDecl baseType = (XSComplexTypeDecl) type;
    fBaseType = baseType;

    // -----------------------------------------------------------------------
    // Check that the base permits the derivation
    // -----------------------------------------------------------------------
    if ((baseType.getFinal() & fDerivedBy) != 0) {
      fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
      fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
      String errorKey = (fDerivedBy == XSConstants.DERIVATION_EXTENSION) ?
          "cos-ct-extends.1.1" : "derivation-ok-restriction.1";
      throw new ComplexTypeRecoverableError(errorKey,
          new Object[]{fName, fBaseType.getName()}, complexContent);
    }

    // -----------------------------------------------------------------------
    // Skip over any potential annotations
    // -----------------------------------------------------------------------
    complexContent = DOMUtil.getFirstChildElement(complexContent);

    if (complexContent != null) {
      // traverse annotation if any
      if (DOMUtil.getLocalName(complexContent).equals(SchemaSymbols.ELT_ANNOTATION)) {
        addAnnotation(
            traverseAnnotationDecl(complexContent, derivationTypeAttrValues, false, schemaDoc));
        complexContent = DOMUtil.getNextSiblingElement(complexContent);
      } else {
        String text = DOMUtil.getSyntheticAnnotation(complexContent);
        if (text != null) {
          addAnnotation(
              traverseSyntheticAnnotation(complexContent, text, derivationTypeAttrValues, false,
                  schemaDoc));
        }
      }
      if (complexContent != null &&
          DOMUtil.getLocalName(complexContent).equals(SchemaSymbols.ELT_ANNOTATION)) {
        fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
        fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
        throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
            new Object[]{fName, SchemaSymbols.ELT_ANNOTATION}, complexContent);
      }
    } else {
      String text = DOMUtil.getSyntheticAnnotation(complexContent);
      if (text != null) {
        addAnnotation(
            traverseSyntheticAnnotation(complexContent, text, derivationTypeAttrValues, false,
                schemaDoc));
      }
    }
    // -----------------------------------------------------------------------
    // Process the content.  Note:  should I try to catch any complexType errors
    // here in order to return the attr array?
    // -----------------------------------------------------------------------
    try {
      processComplexContent(complexContent, mixedContent, true, schemaDoc,
          grammar);
    } catch (ComplexTypeRecoverableError e) {
      fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
      fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
      throw e;
    }

    // -----------------------------------------------------------------------
    // Compose the final content and attribute uses
    // -----------------------------------------------------------------------
    XSParticleDecl baseContent = (XSParticleDecl) baseType.getParticle();
    if (fDerivedBy == XSConstants.DERIVATION_RESTRICTION) {

      // This is an RESTRICTION

      // N.B. derivation-ok-restriction.5.3 is checked under schema
      // full checking.   That's because we need to wait until locals are
      // traversed so that occurrence information is correct.

      if (fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED &&
          baseType.getContentType() != XSComplexTypeDecl.CONTENTTYPE_MIXED) {
        fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
        fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
        throw new ComplexTypeRecoverableError("derivation-ok-restriction.5.4.1.2",
            new Object[]{fName, baseType.getName()},
            complexContent);
      }

      try {
        mergeAttributes(baseType.getAttrGrp(), fAttrGrp, fName, false, complexContent);
      } catch (ComplexTypeRecoverableError e) {
        fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
        fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
        throw e;
      }
      // Remove prohibited uses.   Must be done after merge for RESTRICTION.
      fAttrGrp.removeProhibitedAttrs();

      if (baseType != SchemaGrammar.fAnyType) {
        Object[] errArgs = fAttrGrp.validRestrictionOf(fName, baseType.getAttrGrp());
        if (errArgs != null) {
          fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
          fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
          throw new ComplexTypeRecoverableError((String) errArgs[errArgs.length - 1],
              errArgs, complexContent);
        }
      }
    } else {

      // This is an EXTENSION

      // Create the particle
      if (fParticle == null) {
        fContentType = baseType.getContentType();
        fXSSimpleType = (XSSimpleType) baseType.getSimpleType();
        fParticle = baseContent;
      } else if (baseType.getContentType() == XSComplexTypeDecl.CONTENTTYPE_EMPTY) {
      } else {
        //
        // Check if the contentType of the base is consistent with the new type
        // cos-ct-extends.1.4.3.2
        if (fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT &&
            baseType.getContentType() != XSComplexTypeDecl.CONTENTTYPE_ELEMENT) {
          fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
          fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
          throw new ComplexTypeRecoverableError("cos-ct-extends.1.4.3.2.2.1.a",
              new Object[]{fName}, complexContent);
        } else if (fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED &&
            baseType.getContentType() != XSComplexTypeDecl.CONTENTTYPE_MIXED) {
          fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
          fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
          throw new ComplexTypeRecoverableError("cos-ct-extends.1.4.3.2.2.1.b",
              new Object[]{fName}, complexContent);
        }

        // if the content of either type is an "all" model group, error.
        if (fParticle.fType == XSParticleDecl.PARTICLE_MODELGROUP &&
            ((XSModelGroupImpl) fParticle.fValue).fCompositor == XSModelGroupImpl.MODELGROUP_ALL ||
            ((XSParticleDecl) baseType.getParticle()).fType == XSParticleDecl.PARTICLE_MODELGROUP &&
                ((XSModelGroupImpl) (((XSParticleDecl) baseType.getParticle())).fValue).fCompositor
                    == XSModelGroupImpl.MODELGROUP_ALL) {
          fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
          fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
          throw new ComplexTypeRecoverableError("cos-all-limited.1.2",
              new Object[]{}, complexContent);
        }
        // the "sequence" model group to contain both particles
        XSModelGroupImpl group = new XSModelGroupImpl();
        group.fCompositor = XSModelGroupImpl.MODELGROUP_SEQUENCE;
        group.fParticleCount = 2;
        group.fParticles = new XSParticleDecl[2];
        group.fParticles[0] = (XSParticleDecl) baseType.getParticle();
        group.fParticles[1] = fParticle;
        group.fAnnotations = XSObjectListImpl.EMPTY_LIST;
        // the particle to contain the above sequence
        XSParticleDecl particle = new XSParticleDecl();
        particle.fType = XSParticleDecl.PARTICLE_MODELGROUP;
        particle.fValue = group;
        particle.fAnnotations = XSObjectListImpl.EMPTY_LIST;

        fParticle = particle;
      }

      // Remove prohibited uses.   Must be done before merge for EXTENSION.
      fAttrGrp.removeProhibitedAttrs();
      try {
        mergeAttributes(baseType.getAttrGrp(), fAttrGrp, fName, true, complexContent);
      } catch (ComplexTypeRecoverableError e) {
        fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
        fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);
        throw e;
      }

    }

    // and *finally* we can legitimately return the attributes!
    fAttrChecker.returnAttrArray(complexContentAttrValues, schemaDoc);
    fAttrChecker.returnAttrArray(derivationTypeAttrValues, schemaDoc);

  } // end of traverseComplexContent


  // This method merges attribute uses from the base, into the derived set.
  // LM: may want to merge with attributeGroup processing.
  private void mergeAttributes(XSAttributeGroupDecl fromAttrGrp,
      XSAttributeGroupDecl toAttrGrp,
      String typeName,
      boolean extension,
      Element elem)
      throws ComplexTypeRecoverableError {

    XSObjectList attrUseS = fromAttrGrp.getAttributeUses();
    XSAttributeUseImpl oneAttrUse = null;
    int attrCount = attrUseS.getLength();
    for (int i = 0; i < attrCount; i++) {
      oneAttrUse = (XSAttributeUseImpl) attrUseS.item(i);
      XSAttributeUse existingAttrUse = toAttrGrp
          .getAttributeUse(oneAttrUse.fAttrDecl.getNamespace(),
              oneAttrUse.fAttrDecl.getName());
      if (existingAttrUse == null) {

        String idName = toAttrGrp.addAttributeUse(oneAttrUse);
        if (idName != null) {
          throw new ComplexTypeRecoverableError("ct-props-correct.5",
              new Object[]{typeName, idName, oneAttrUse.fAttrDecl.getName()},
              elem);
        }
      } else if (existingAttrUse != oneAttrUse) {
        if (extension) {
          reportSchemaError("ct-props-correct.4",
              new Object[]{typeName, oneAttrUse.fAttrDecl.getName()},
              elem);
          // Recover by using the attribute use from the base type,
          // to make the resulting schema "more valid".
          toAttrGrp.replaceAttributeUse(existingAttrUse, oneAttrUse);
        }
      }
    }
    // For extension, the wildcard must be formed by doing a union of the wildcards
    if (extension) {
      if (toAttrGrp.fAttributeWC == null) {
        toAttrGrp.fAttributeWC = fromAttrGrp.fAttributeWC;
      } else if (fromAttrGrp.fAttributeWC != null) {
        toAttrGrp.fAttributeWC = toAttrGrp.fAttributeWC
            .performUnionWith(fromAttrGrp.fAttributeWC, toAttrGrp.fAttributeWC.fProcessContents);
        if (toAttrGrp.fAttributeWC == null) {
          // REVISIT: XML Schema 1.0 2nd edition doesn't actually specify this constraint. It's a bug in the spec
          // which will eventually be fixed. We're just guessing what the error code will be. If it turns out to be
          // something else we'll need to change it. -- mrglavas
          throw new ComplexTypeRecoverableError("src-ct.5", new Object[]{typeName}, elem);
        }
      }

    }
  }

  private void processComplexContent(Element complexContentChild,
      boolean isMixed, boolean isDerivation,
      XSDocumentInfo schemaDoc, SchemaGrammar grammar)
      throws ComplexTypeRecoverableError {

    Element attrNode = null;
    XSParticleDecl particle = null;

    // whether there is a particle with empty model group
    boolean emptyParticle = false;
    if (complexContentChild != null) {
      // -------------------------------------------------------------
      // GROUP, ALL, SEQUENCE or CHOICE, followed by attributes, if specified.
      // Note that it's possible that only attributes are specified.
      // -------------------------------------------------------------

      String childName = DOMUtil.getLocalName(complexContentChild);

      if (childName.equals(SchemaSymbols.ELT_GROUP)) {

        particle = fSchemaHandler.fGroupTraverser.traverseLocal(complexContentChild,
            schemaDoc, grammar);
        attrNode = DOMUtil.getNextSiblingElement(complexContentChild);
      } else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) {
        particle = traverseSequence(complexContentChild, schemaDoc, grammar,
            NOT_ALL_CONTEXT, fComplexTypeDecl);
        if (particle != null) {
          XSModelGroupImpl group = (XSModelGroupImpl) particle.fValue;
          if (group.fParticleCount == 0) {
            emptyParticle = true;
          }
        }
        attrNode = DOMUtil.getNextSiblingElement(complexContentChild);
      } else if (childName.equals(SchemaSymbols.ELT_CHOICE)) {
        particle = traverseChoice(complexContentChild, schemaDoc, grammar,
            NOT_ALL_CONTEXT, fComplexTypeDecl);
        if (particle != null && particle.fMinOccurs == 0) {
          XSModelGroupImpl group = (XSModelGroupImpl) particle.fValue;
          if (group.fParticleCount == 0) {
            emptyParticle = true;
          }
        }
        attrNode = DOMUtil.getNextSiblingElement(complexContentChild);
      } else if (childName.equals(SchemaSymbols.ELT_ALL)) {
        particle = traverseAll(complexContentChild, schemaDoc, grammar,
            PROCESSING_ALL_GP, fComplexTypeDecl);
        if (particle != null) {
          XSModelGroupImpl group = (XSModelGroupImpl) particle.fValue;
          if (group.fParticleCount == 0) {
            emptyParticle = true;
          }
        }
        attrNode = DOMUtil.getNextSiblingElement(complexContentChild);
      } else {
        // Should be attributes here - will check below...
        attrNode = complexContentChild;
      }
    }

    // if the particle is empty because there is no non-annotation chidren,
    // we need to make the particle itself null (so that the effective
    // content is empty).
    if (emptyParticle) {
      // get the first child
      Element child = DOMUtil.getFirstChildElement(complexContentChild);
      // if it's annotation, get the next one
      if (child != null) {
        if (DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
          child = DOMUtil.getNextSiblingElement(child);
        }
      }
      // if there is no (non-annotation) children, mark particle empty
      if (child == null) {
        particle = null;
      }
      // child != null means we might have seen an element with
      // minOccurs == maxOccurs == 0
    }

    if (particle == null && isMixed) {
      particle = XSConstraints.getEmptySequence();
    }
    fParticle = particle;

    // -----------------------------------------------------------------------
    // Set the content type
    // -----------------------------------------------------------------------
    if (fParticle == null) {
      fContentType = XSComplexTypeDecl.CONTENTTYPE_EMPTY;
    } else if (isMixed) {
      fContentType = XSComplexTypeDecl.CONTENTTYPE_MIXED;
    } else {
      fContentType = XSComplexTypeDecl.CONTENTTYPE_ELEMENT;
    }

    // -------------------------------------------------------------
    // Now, process attributes
    // -------------------------------------------------------------
    if (attrNode != null) {
      if (!isAttrOrAttrGroup(attrNode)) {
        throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
            new Object[]{fName, DOMUtil.getLocalName(attrNode)},
            attrNode);
      }
      Element node =
          traverseAttrsAndAttrGrps(attrNode, fAttrGrp, schemaDoc, grammar, fComplexTypeDecl);
      if (node != null) {
        throw new ComplexTypeRecoverableError("s4s-elt-invalid-content.1",
            new Object[]{fName, DOMUtil.getLocalName(node)},
            node);
      }
      // Only remove prohibited attribute uses if this isn't a derived type
      // Derivation-specific code worries about this elsewhere
      if (!isDerivation) {
        fAttrGrp.removeProhibitedAttrs();
      }
    }


  } // end processComplexContent


  private boolean isAttrOrAttrGroup(Element e) {
    String elementName = DOMUtil.getLocalName(e);

    if (elementName.equals(SchemaSymbols.ELT_ATTRIBUTE) ||
        elementName.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP) ||
        elementName.equals(SchemaSymbols.ELT_ANYATTRIBUTE)) {
      return true;
    } else {
      return false;
    }
  }

  private void traverseSimpleContentDecl(Element simpleContentDecl) {
  }

  private void traverseComplexContentDecl(Element complexContentDecl,
      boolean mixedOnComplexTypeDecl) {
  }

  /*
   * Generate a name for an anonymous type
   */
  private String genAnonTypeName(Element complexTypeDecl) {

    // Generate a unique name for the anonymous type by concatenating together the
    // names of parent nodes
    // The name is quite good for debugging/error purposes, but we may want to
    // revisit how this is done for performance reasons (LM).
    StringBuffer typeName = new StringBuffer("#AnonType_");
    Element node = DOMUtil.getParent(complexTypeDecl);
    while (node != null && (node != DOMUtil.getRoot(DOMUtil.getDocument(node)))) {
      typeName.append(node.getAttribute(SchemaSymbols.ATT_NAME));
      node = DOMUtil.getParent(node);
    }
    return typeName.toString();
  }


  private void handleComplexTypeError(String messageId, Object[] args,
      Element e) {

    if (messageId != null) {
      reportSchemaError(messageId, args, e);
    }

    //
    //  Mock up the typeInfo structure so that there won't be problems during
    //  validation
    //
    fBaseType = SchemaGrammar.fAnyType;
    fContentType = XSComplexTypeDecl.CONTENTTYPE_MIXED;
    fXSSimpleType = null;
    fParticle = getErrorContent();
    // REVISIT: do we need to remove all attribute uses already added into
    // the attribute group? maybe it's ok to leave them there. -SG
    fAttrGrp.fAttributeWC = getErrorWildcard();

    return;

  }

  private void contentBackup() {
    if (fGlobalStore == null) {
      fGlobalStore = new Object[GLOBAL_NUM];
      fGlobalStorePos = 0;
    }
    if (fGlobalStorePos == fGlobalStore.length) {
      Object[] newArray = new Object[fGlobalStorePos + GLOBAL_NUM];
      System.arraycopy(fGlobalStore, 0, newArray, 0, fGlobalStorePos);
      fGlobalStore = newArray;
    }
    fGlobalStore[fGlobalStorePos++] = fComplexTypeDecl;
    fGlobalStore[fGlobalStorePos++] = fIsAbstract ? Boolean.TRUE : Boolean.FALSE;
    fGlobalStore[fGlobalStorePos++] = fName;
    fGlobalStore[fGlobalStorePos++] = fTargetNamespace;
    // let's save ourselves a couple of objects...
    fGlobalStore[fGlobalStorePos++] = new Integer((fDerivedBy << 16) + fFinal);
    fGlobalStore[fGlobalStorePos++] = new Integer((fBlock << 16) + fContentType);
    fGlobalStore[fGlobalStorePos++] = fBaseType;
    fGlobalStore[fGlobalStorePos++] = fAttrGrp;
    fGlobalStore[fGlobalStorePos++] = fParticle;
    fGlobalStore[fGlobalStorePos++] = fXSSimpleType;
    fGlobalStore[fGlobalStorePos++] = fAnnotations;
  }

  private void contentRestore() {
    fAnnotations = (XSAnnotationImpl[]) fGlobalStore[--fGlobalStorePos];
    fXSSimpleType = (XSSimpleType) fGlobalStore[--fGlobalStorePos];
    fParticle = (XSParticleDecl) fGlobalStore[--fGlobalStorePos];
    fAttrGrp = (XSAttributeGroupDecl) fGlobalStore[--fGlobalStorePos];
    fBaseType = (XSTypeDefinition) fGlobalStore[--fGlobalStorePos];
    int i = ((Integer) (fGlobalStore[--fGlobalStorePos])).intValue();
    fBlock = (short) (i >> 16);
    fContentType = (short) i;
    i = ((Integer) (fGlobalStore[--fGlobalStorePos])).intValue();
    fDerivedBy = (short) (i >> 16);
    fFinal = (short) i;
    fTargetNamespace = (String) fGlobalStore[--fGlobalStorePos];
    fName = (String) fGlobalStore[--fGlobalStorePos];
    fIsAbstract = ((Boolean) fGlobalStore[--fGlobalStorePos]).booleanValue();
    fComplexTypeDecl = (XSComplexTypeDecl) fGlobalStore[--fGlobalStorePos];
  }

  private void addAnnotation(XSAnnotationImpl annotation) {
    if (annotation == null) {
      return;
    }
    // it isn't very likely that there will be more than one annotation
    // in a complexType decl.  This saves us fromhaving to push/pop
    // one more object from the fGlobalStore, and that's bound
    // to be a savings for most applications
    if (fAnnotations == null) {
      fAnnotations = new XSAnnotationImpl[1];
    } else {
      XSAnnotationImpl[] tempArray = new XSAnnotationImpl[fAnnotations.length + 1];
      System.arraycopy(fAnnotations, 0, tempArray, 0, fAnnotations.length);
      fAnnotations = tempArray;
    }
    fAnnotations[fAnnotations.length - 1] = annotation;
  }
}
